#include "Common.h"
#include "InputManager.h"

#define STRICT
#define DIRECTINPUT_VERSION 0x0800
#include <dinput.h>

InputManager::InputManager(void)
	: mDirectInput(NULL)
	, mMouseDevice(NULL)
	, mWnd(NULL)
	, mActive(true)
	, mImmediateMode(false)
{
}

InputManager::~InputManager(void)
{
	SAFE_RELEASE(mMouseDevice);
	SAFE_RELEASE(mDirectInput);
}

bool InputManager::Init(void* hWnd)
{
	mWnd = hWnd;

	DirectInput8Create(
		GetModuleHandle(NULL),
		DIRECTINPUT_VERSION,
		IID_IDirectInput8,
		(VOID**)&mDirectInput,
		NULL);

	if (mDirectInput == NULL)
		return false;

	mDirectInput->CreateDevice(GUID_SysMouse, &mMouseDevice, NULL);
	if (mMouseDevice == NULL)
		return false;

	mMouseDevice->SetDataFormat(&c_dfDIMouse2);
	mMouseDevice->SetCooperativeLevel((HWND)hWnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND);

	return true;
}

void InputManager::setImmediateMode(bool v)
{
	mImmediateMode = v;

	if (mImmediateMode)
		mMouseDevice->Acquire();
	else
	{
		mMouseDevice->Unacquire();

		RECT rect;
		if (::GetWindowRect((HWND)mWnd, &rect))
			::SetCursorPos((rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2);
	}
}

void InputManager::CheckMouseInput()
{
	mMouseDevice->Acquire();
	
	// get current mouse status.
	DIMOUSESTATE2 mouseStatus;
	mMouseDevice->GetDeviceState(sizeof(mouseStatus), &mouseStatus);

	// save to the latest.
	OnMouseMove(mouseStatus.lX, mouseStatus.lY);
}

void InputManager::Update(float elapsedTime)
{
	if (mActive)
	{
		if (mImmediateMode)
			CheckMouseInput();
	}
}

void InputManager::AddListener(Listener* listener)
{
	mListeners.push_back(listener);
}

void InputManager::RemoveListener(Listener* listener)
{
	mListeners.remove(listener);
}

void InputManager::OnMouseMove(long deltaX, long deltaY)
{
	for (ListenerList::iterator it(mListeners.begin()), end(mListeners.end()); it != end; it++)
		if ((*it)->OnMouseMove(deltaX, deltaY))
			break;
}


bool InputManager::MsgProc(void* hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	if (msg == WM_DESTROY)
	{
        PostQuitMessage(0);
        return true;
	}

	for (ListenerList::iterator it(mListeners.begin()), end(mListeners.end()); it != end; it++)
		if ((*it)->MsgProc(hWnd, msg, wParam, lParam))
			return true;
	return false;
}